
package com.hlkj.pay.app.ad.impl;

import java.math.BigDecimal;
import java.util.Random;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.framework.common.util.web.WebFrameworkUtils;
import com.hlkj.pay.app.ad.IAdPayOrderAppService;
import com.hlkj.pay.app.ad.IAdRefundOrderAppService;
import com.hlkj.pay.app.ad.IAdStatisticsAppService;
import com.hlkj.pay.app.ad.constant.AdConstant;
import com.hlkj.pay.app.order.impl.OrderHandler;
import com.hlkj.pay.common.AdResultCode;
import com.hlkj.pay.common.CommonResultCode;
import com.hlkj.pay.dto.ad.query.HlPayOrderQueryResultDto;
import com.hlkj.pay.dto.ad.result.HlPayDataResultDto;
import com.hlkj.pay.dto.common.OrderStatusDto;
import com.hlkj.pay.enums.CommonEnum;
import com.hlkj.pay.enums.PayOrderEnums;
import com.hlkj.pay.gateway.ad.IAdOrderGateway;
import com.hlkj.pay.infrastructure.model.ad.AdInfoConfigDO;
import com.hlkj.pay.infrastructure.model.ad.AdInfoDO;
import com.hlkj.pay.infrastructure.model.ad.AdPayOrderDO;
import com.hlkj.pay.service.ad.IAdInfoService;
import com.hlkj.pay.service.ad.IAdPayOrderService;
import com.hlkj.pay.util.AdUtils;
import com.hlkj.pay.util.MerchantUtils;
import com.hlkj.pay.util.OrderCodeUtil;
import com.hlkj.pay.vo.ad.req.AdSubmitOrderReq;
import com.hlkj.pay.vo.ad.resp.AdH5Resp;
import com.hlkj.pay.vo.ad.resp.AdPayOrderResp;

import cn.hutool.extra.servlet.ServletUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author HlpayTeam
 * @date 2024/10/23 14:22
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AdPayOrderAppServiceImpl implements IAdPayOrderAppService {

    private final IAdInfoService adInfoService;

    private final IAdPayOrderService adPayOrderService;

    private final OrderHandler orderHandler;

    private final OrderCodeUtil orderCodeUtil;

    private final IAdStatisticsAppService adStatisticsAppService;

    private final AdPayOrderMessageHandler adPayOrderMessageHandler;

    private final AdPayOrderHandler adPayOrderHandler;

    private final IAdRefundOrderAppService adRefundOrderAppService;

    private final IAdOrderGateway adOrderGateway;

    @Value("${rocketmq.consumer.ad_order_delay_consumer_count:5}")
    private Integer orderDelayConsumerCount;

    @Override
    public CommonResult<AdPayOrderResp> submitOrder(AdSubmitOrderReq adSubmitOrderReq) {
        log.info("submitOrder adSubmitOrderReq:{}", adSubmitOrderReq);
        try {
            AdInfoDO adInfoDO = adInfoService.queryById(adSubmitOrderReq.getAdId());
            if (adInfoDO == null) {
                return CommonResult.error(AdResultCode.AD_NOT_EXITS);
            }
            AdInfoConfigDO adInfoConfigDO = adInfoService.queryConfigByAdId(adSubmitOrderReq.getAdId());
            if (adInfoConfigDO == null) {
                return CommonResult.error(AdResultCode.AD_NOT_EXITS);
            }
            AdPayOrderDO payOrderDO = buildAdPayOrderDO(adSubmitOrderReq, adInfoDO, adInfoConfigDO);
            AdPayOrderResp adPayOrderResp = buildAdPayOrderDOResp(payOrderDO);
            // 发起post请求
            HlPayDataResultDto hlPayDataResultDto = adOrderGateway.submitPayOrder(payOrderDO, adInfoDO, adInfoConfigDO);
            if (hlPayDataResultDto != null) {
                if (hlPayDataResultDto.getCode() != null && hlPayDataResultDto.getCode() == 1) {
                    HlPayDataResultDto.DataBean payDataDtoData = hlPayDataResultDto.getData();
                    if (payDataDtoData.getPay_order_id() != null) {
                        payOrderDO.setPayOrderNo(payDataDtoData.getPay_order_id());
                    }
                    payOrderDO.setState(PayOrderEnums.PAY_ORDER_STATUS.PAYING.getCode());
                    adPayOrderResp.setPayInfo(payDataDtoData.getPay_info());
                }
                else {
                    payOrderDO.setRemark(hlPayDataResultDto.getMsg());
                    payOrderDO.setState(PayOrderEnums.PAY_ORDER_STATUS.FAIL.getCode());
                    log.warn("汇联支付生成失败:{}" + JsonUtils.toJsonString(hlPayDataResultDto));
                }
            }
            adPayOrderService.addPayOrder(payOrderDO);
            adPayOrderMessageHandler.submitOrder(payOrderDO);
            if (adPayOrderResp.getPayInfo() == null) {
                return CommonResult.error(AdResultCode.PAY_ORDER_FAIL.getCode(), payOrderDO.getRemark());
            }
            return CommonResult.success(adPayOrderResp);
        }
        catch (Exception e) {
            e.printStackTrace();
            log.error("submitOrder error:{}", e.getMessage(),e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }

    }

    @Override
    public CommonResult<AdH5Resp> adInfo(Long id) {
        AdH5Resp adH5Resp = new AdH5Resp();
        AdInfoDO adInfoDO = adInfoService.queryById(id);
        if (adInfoDO == null) {
            return CommonResult.error(AdResultCode.AD_NOT_EXITS);
        }
        if (CommonEnum.YES_NO_TYPE.NO.getCode().equals(adInfoDO.getStatus())) {
            return CommonResult.error(AdResultCode.AD_NOT_EXITS);
        }
        AdInfoConfigDO adInfoConfigDO = adInfoService.queryConfigByAdId(id);
        if (adInfoConfigDO == null) {
            return CommonResult.error(AdResultCode.AD_NOT_EXITS);
        }
        adH5Resp.setId(id);
        adH5Resp.setAmount(adInfoDO.getAmount());
        adH5Resp.setType(adInfoDO.getType());
        adH5Resp.setPayTypes(adInfoConfigDO.getPayTypes());
        for (int i = 0; i < 20; i++) {
            adH5Resp.getPhoneList().add(AdUtils.phone());
        }
        adH5Resp.setReturnUrl(adInfoDO.getReturnUrl());
        adStatisticsAppService.addView(id);
        return CommonResult.success(adH5Resp);
    }

    @Override
    public void processOrderStatusMessage(OrderStatusDto orderStatusDto) {
        PayOrderEnums.ORDER_STATUS_TYPE orderStatusType = PayOrderEnums.ORDER_STATUS_TYPE.from(orderStatusDto.getOrderStatusType());
        boolean needSend = false;
        String orderNo = orderStatusDto.getOrderNo();
        if (!StringUtils.hasText(orderNo)) {
            log.info("收到的数据错误 orderNo:{}", orderNo);
            return;
        }
        switch (orderStatusType) {
            case PAY_ORDER_STATUS:
                needSend = queryOrderStatus(orderNo, orderStatusDto.getTotalConsumerCount());
                break;
            case REFUND_STATUS:
                needSend = adRefundOrderAppService.queryRefundStatus(orderNo);
                break;
            case ORDER_CLOSE:
                AdPayOrderDO payOrderDO = adPayOrderService.queryDetailCache(orderNo);
                PayOrderEnums.PAY_ORDER_STATUS payOrderStatus = PayOrderEnums.PAY_ORDER_STATUS.from(payOrderDO.getState());
                switch (payOrderStatus) {
                    case PAYING:
                        AdPayOrderDO updatePayOrderDO = new AdPayOrderDO();
                        updatePayOrderDO.setId(payOrderDO.getId());
                        updatePayOrderDO.setState(PayOrderEnums.PAY_ORDER_STATUS.CLOSE.getCode());
                        adPayOrderService.updatePayOrder(payOrderDO.getMchOrderNo(), updatePayOrderDO);
                        break;
                }
                break;
        }
        // 没有查询到结果 重新丢到队列中
        if (needSend) {
            log.info("当前订单状态未变更,需要重新丢到延迟队列 orderNo:{}", orderNo);
            adPayOrderMessageHandler.sendAdOrderStatus(orderStatusDto);
        }
    }

    @Override
    public CommonResult<AdPayOrderResp> queryDetail(String mchOrderNo) {
        AdPayOrderDO payOrderDO = adPayOrderService.queryDetailCache(mchOrderNo);
        if (payOrderDO == null) {
            return CommonResult.error(AdResultCode.PAY_ORDER_NOT_EXITS);
        }
        PayOrderEnums.PAY_ORDER_STATUS payOrderStatus = PayOrderEnums.PAY_ORDER_STATUS.from(payOrderDO.getState());
        switch (payOrderStatus) {
            case PAYING:
                queryOrderStatus(payOrderDO);
                payOrderDO = adPayOrderService.queryDetail(mchOrderNo);
                break;
        }
        return CommonResult.success(buildAdPayOrderDOResp(payOrderDO));
    }

    boolean queryOrderStatus(String mchOrderNo, Integer delayConsumerCount) {
        AdPayOrderDO payOrderDO = adPayOrderService.queryDetailCache(mchOrderNo);
        if (payOrderDO == null) {
            return false;
        }
        PayOrderEnums.PAY_ORDER_STATUS payOrderStatus = PayOrderEnums.PAY_ORDER_STATUS.from(payOrderDO.getState());
        switch (payOrderStatus) {
            case PAYING:
                Long expiredTime = payOrderDO.getExpiredTime();
                if (expiredTime == null) {
                    expiredTime = payOrderDO.getCreateTime() + AdConstant.EXPIRE_TIME;
                }
                boolean closeOrderStatus = false;
                boolean queryOrderStatus = false;
                // 当前时间小于失效时间,才查询订单状态
                if (System.currentTimeMillis() < expiredTime) {
                    queryOrderStatus = queryOrderStatus(payOrderDO);
                    // 消费次数过多 关闭订单
                    if (queryOrderStatus && delayConsumerCount != null && delayConsumerCount > orderDelayConsumerCount) {
                        closeOrderStatus = true;
                    }
                }
                else {
                    log.info("当前订单已超过失效时间,直接关闭 mchOrderNo:{}", mchOrderNo);
                    closeOrderStatus = true;
                }
                if (closeOrderStatus) {
                    AdPayOrderDO updatePayOrderDO = new AdPayOrderDO();
                    updatePayOrderDO.setId(payOrderDO.getId());
                    updatePayOrderDO.setState(PayOrderEnums.PAY_ORDER_STATUS.CLOSE.getCode());
                    if (payOrderDO.getExpiredTime() == null) {
                        updatePayOrderDO.setExpiredTime(expiredTime);
                    }
                    adPayOrderService.updatePayOrder(payOrderDO.getMchOrderNo(), updatePayOrderDO);
                    return false;
                }
                return queryOrderStatus;
        }
        return false;
    }

    boolean queryOrderStatus(AdPayOrderDO payOrderDO) {
        AdInfoConfigDO adInfoConfigDO = adInfoService.queryConfigByAdId(payOrderDO.getAdId());
        try {
            HlPayOrderQueryResultDto payDataDto = adOrderGateway.queryOrder(payOrderDO, adInfoConfigDO);
            log.info("查询支付结果 返回参数 postJson:{}", JsonUtils.toJsonString(payDataDto));
            if (payDataDto != null) {
                if (payDataDto.getCode() != null && payDataDto.getCode() == 1) {
                    HlPayOrderQueryResultDto.PayOrderQueryData payDataDtoData = JsonUtils.parseObject(JsonUtils.toJsonString(payDataDto.getData()),
                            HlPayOrderQueryResultDto.PayOrderQueryData.class);
                    // 订单状态，0=支付失败，1=初始化，2=支付中，3=支付成功，4=已撤销，5=订单关闭
                    PayOrderEnums.PAY_ORDER_STATUS orderStatus = null;
                    switch (payDataDtoData.getState()) {
                        case "3":
                            orderStatus = PayOrderEnums.PAY_ORDER_STATUS.SUCCESS;
                            break;
                        case "4":
                            orderStatus = PayOrderEnums.PAY_ORDER_STATUS.CANCEL;
                            break;
                        case "5":
                            orderStatus = PayOrderEnums.PAY_ORDER_STATUS.CLOSE;
                            break;
                    }
                    if (orderStatus != null) {
                        AdPayOrderDO updatePayOrderDO = new AdPayOrderDO();
                        if (StringUtils.hasText(payDataDtoData.getAmount())) {
                            updatePayOrderDO.setPayAmount(new BigDecimal(payDataDtoData.getAmount()));
                            payOrderDO.setPayAmount(updatePayOrderDO.getPayAmount());
                        }
                        updatePayOrderDO.setId(payOrderDO.getId());
                        updatePayOrderDO.setState(orderStatus.getCode());
                        updatePayOrderDO.setInsOrderNo(payDataDtoData.getIns_order_sn());
                        if (payDataDtoData.getSuccess_time() != null) {
                            updatePayOrderDO.setSuccessTime(Long.valueOf(payDataDtoData.getSuccess_time()) * 1000l);
                        }
                        updatePayOrderDO.setChannelOrderNo(payDataDtoData.getChannel_order_sn());
                        int payOrderStatus = adPayOrderService.updatePayOrderStatus(payOrderDO.getMchOrderNo(), updatePayOrderDO);
                        if (payOrderStatus > 0) {
                            switch (orderStatus) {
                                case SUCCESS:
                                    adPayOrderHandler.paySuccess(payOrderDO);
                                    break;
                            }
                        }
                        return false;
                    }
                    else {
                        return true;
                    }
                }
                else {
                    return true;
                }
            }
        }
        catch (Exception e) {
            log.info("订单查询出错:{}", e.getMessage());
            return true;
        }
        return true;
    }

    AdPayOrderDO buildAdPayOrderDO(AdSubmitOrderReq adSubmitOrderReq, AdInfoDO adInfoDO, AdInfoConfigDO adInfoConfigDO) {
        // 获取request
        HttpServletRequest request = WebFrameworkUtils.getRequest();
        AdPayOrderDO adPayOrderDO = new AdPayOrderDO();
        adPayOrderDO.setMchOrderNo(orderCodeUtil.orderNo(PayOrderEnums.ORDER_NO_TYPE.ORDER));
        adPayOrderDO.setAdId(adInfoDO.getId());
        adPayOrderDO.setPayType(adSubmitOrderReq.getPayType());
        // adPayOrderDO.setPaySubType(adSubmitOrderReq.getPaySubType());

        Random random = new Random();
        int nextDouble = random.nextInt(201);
        log.info("优惠金额 mchOrderNo:{},nextDouble:{}", adPayOrderDO.getMchOrderNo(), nextDouble);
        if (adInfoDO.getAmount().compareTo(new BigDecimal(nextDouble)) > 0) {
            adPayOrderDO.setAmount(MerchantUtils.subtract(adInfoDO.getAmount(), MerchantUtils.fenToYuan(nextDouble)));
        }
        else {
            adPayOrderDO.setAmount(adInfoDO.getAmount());
        }
        if (StringUtils.hasText(adInfoDO.getGoodsName())) {
            adPayOrderDO.setSubject(adInfoDO.getGoodsName());
            adPayOrderDO.setDescription(adInfoDO.getGoodsName());
        }
        else {
            adPayOrderDO.setSubject(adInfoDO.getName());
            adPayOrderDO.setDescription(adInfoDO.getName());
        }
        adPayOrderDO.setClientIp(ServletUtil.getClientIP(request, null));
        adPayOrderDO.setState(PayOrderEnums.PAY_ORDER_STATUS.INIT.getCode());
        adPayOrderDO.setSn(adInfoConfigDO.getSn());
        adPayOrderDO.setAppId(adInfoConfigDO.getAppId());
        adPayOrderDO.setPhone(adSubmitOrderReq.getPhone());
        adPayOrderDO.setRefundStatus(PayOrderEnums.ORDER_REFUND_STATUS.NO_REFUND.getCode());
        adPayOrderDO.setRefundAmount(new BigDecimal("0"));
        adPayOrderDO.setCallStatus(CommonEnum.YES_NO_TYPE.NO.getCode());
        adPayOrderDO.setOrderSource(1);
        adPayOrderDO.setTuiId(adSubmitOrderReq.getTuiId());
        adPayOrderDO.setExpiredTime(System.currentTimeMillis() + AdConstant.EXPIRE_TIME);
        return adPayOrderDO;
    }

    AdPayOrderResp buildAdPayOrderDOResp(AdPayOrderDO adPayOrderDO) {
        // 获取request
        AdPayOrderResp adPayOrderResp = new AdPayOrderResp();
        adPayOrderResp.setPayOrderNo(adPayOrderDO.getPayOrderNo());
        adPayOrderResp.setMchOrderNo(adPayOrderDO.getMchOrderNo());
        adPayOrderResp.setAdId(adPayOrderDO.getAdId());
        adPayOrderResp.setPayType(adPayOrderDO.getPayType());
        adPayOrderResp.setPaySubType(adPayOrderDO.getPaySubType());
        adPayOrderResp.setAmount(adPayOrderDO.getAmount());
        adPayOrderResp.setClientIp(adPayOrderDO.getClientIp());
        adPayOrderResp.setSubject(adPayOrderDO.getSubject());
        adPayOrderResp.setDescription(adPayOrderDO.getDescription());
        adPayOrderResp.setState(adPayOrderDO.getState());
        adPayOrderResp.setExpiredTime(adPayOrderDO.getExpiredTime());
        // adPayOrderResp.setSn(adPayOrderDO.getSn());
        // adPayOrderResp.setAppId(adPayOrderDO.getAppId());
        // adPayOrderResp.setPhone();

        return adPayOrderResp;
    }

    public static void main(String[] args) {
        BigDecimal payAmount = new BigDecimal("1");
        BigDecimal nextDouble = new BigDecimal("0.09");
        System.out.println(payAmount.compareTo(nextDouble));
    }
}
